package com.tools.web.interceptor.limit;

import com.tools.common.object.Note;
import com.tools.common.thread.Timeunit;
import com.tools.middle.redis.client.JedisPlus;
import com.tools.web.interceptor.auth.AuthenticationManager;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Objects;

/**
 * 使用 JedisPlus 客户端操作单机 Redis 实现的 IP-URI 同 IP 请求同一个接口的请求限流拦截器
 * */
@Note("使用 JedisPlus 客户端操作单机 Redis 实现的 IP-URI 同 IP 请求同一个接口的请求限流拦截器")
public final class JedisPlusRequestLimitInterceptor extends AbsRequestLimitInterceptor implements RequestLimitRedisLuaScript {

    @Note("操作 Redis 的单机客户端")
    private final JedisPlus jedisPlus;

    public JedisPlusRequestLimitInterceptor(JedisPlus jedisPlus, RequestLimitSource source) {
        this(jedisPlus, source, null);
    }

    public JedisPlusRequestLimitInterceptor(JedisPlus jedisPlus, RequestLimitSource source, AuthenticationManager authenticationManager) {
        super(source, authenticationManager);
        this.jedisPlus = Objects.requireNonNull(jedisPlus, "操作 Redis 的单机客户端 JedisPlus 不能为 null");
    }


    @Override
    protected boolean protected_checkIsAllow(RequestLimit limit, HttpServletRequest request, HttpServletResponse response,
                                             AuthenticationManager authenticationManager) throws Exception {
        String key = super.protected_getKey(request);
        long time = limit.time();
        Timeunit timeunit = limit.timeunit();
        long expiration = Timeunit.toSecond(time, timeunit);
        try {
            Long result = (Long) this.jedisPlus.eval(CHECK_LIMIT, 1, key, expiration, limit.allow());
            if(result != null && result == 1) return true;
            response.getWriter().write(super.getLimitErrorMessage());
            if(authenticationManager != null) {
                authenticationManager.handleDisable(request);
            }
            return false;
        } finally {
            this.jedisPlus.close();
        }
    }
}
